/**Class Matrix For basic manipulation on matrix 
*
*
* 
* @author : Vishwajeet Dusane 
*/

#include<stdio.h>
#include<math.h>
#include<fstream.h>
#include<iostream.h>

class Matrix
{
   public:
   
   
  double matrix[100][100]; 
  
  int row,column;
  
   // Constructor
   Matrix();
   
   // Constructor
   //matrix of size n rows 
   Matrix(int);
   
   // Constructor
   //  matrix of size n (rows) * m (column) 
   Matrix(int,int);
   
   // Destructor
   ~Matrix();
   
  
  //read Matrix from file
  int readMatrix(char [50]);
  
  
  //use default matrix
   void useDefault();
   
  //swap Rows 
  void swapRow(int ,int) ; 
   
  //get elements from keyboard
  void newElement();  
    
  //operator *  overloading for matrix multiplication
 Matrix operator*(const Matrix ); 
 
 
 // operator == overloading for matrix comparison return 1 if two matrices are equal
 int operator==(Matrix ); 
 
 //subtraction of two matrices
 Matrix operator-(const Matrix );  
 
  
 
 // print Matrix   
   void printMatrix();
   
 //print matrix with specified comment
  void printMatrix(char [200]);
     
   
   
 //set row and column
  void setMatrixSize(int ,int );
  
 // return row
 int getRowSize();
 
 //return column size
 int getColumnSize();
      
 // make all entries in matrix 0
 void makeElement(int);
 
 //Solved the augmented matrix and calculate the values for it 
 Matrix getValueOfEquation(Matrix );
    
   
 
  //check whether given matrix is upper triangular or not ,return true
  //  check entries 0 where i>j 
  //    U11 U12 U13
  //    0   U22 U23
  //    0    0  U33 
  int isUpperTriangular();  
  
  
  //return true 1 if matrix is lower triangular 
  //  make entries 0 where i>j 
  int isLowerTriangular();  
  
  // check the tolerence and true if the tolerence is less than 0.0000001  
  int isTolerable( ); 
  
  // check the tolerence and true if the tolerence is less than the specified in as parameter
  //specified tolerence should be in the range of double cause Marix is off size double
 int isTolerable(double);   
  
   };
   
//return mod  
double mod( double);

//return mod of matrix
Matrix mod( Matrix);
  

  double mod( double element)
  {
     if( element<0) 
      return (-1)*element;
     else
     return element; 
  } 
  
  Matrix mod(Matrix temp)
  {
     for(int i=0;i<temp.row;i++)
     {
         for(int j=0;j<temp.column;j++)
	 {
             if( temp.matrix[i][j]<0) 
      	  	temp.matrix[i][j]=temp.matrix[i][j]*(-1);
	 }
     }
  
   return temp;  
  }
   
     

  //---------------------------------------------------------------------------------------------  
 /* Matrix::Matrix(int row)
  {
    
    row=row;
    column =1;
    
    double **matrix = new double[row][1];
  
    
  }*/
  
 //---------------------------------------------------------------------------------------------- 
  Matrix::Matrix(int rowNumber,int columnNumber)
  {
     
    row=rowNumber;
    column =columnNumber;
  
      //double **matrix = new double[rowNumber][columnNumber];
      
      
      
  
  }
  
  //----------------------------------------------------------------------------------------------
  Matrix::Matrix()
  {
  
    row=3;
    column=3;     
   
  }
  
  
  //---------------------------------------------------------------------------------------------------
  Matrix::~Matrix()
  {
  
     //delete **matrix;
   
  }
 
   
 //----------------------------------------------------------------------------------------------------
 
 int Matrix::readMatrix(char fname[50])
  {
    
    ifstream fin(fname);
     
     if(!fin)
     {
       cout<<"ERROR : While Opening File "<<fname<<endl;
       return 0;
     
     }
     
     fin>>row;
     fin>>column;
     for(int i=0; i<row ;i++)
     {
       for(int j=0;j<column;j++)
        {
            fin>>matrix[i][j];
	} 
     }
    fin.close();
    printMatrix();
    
    return 1; 
  }
  
//----------------------------------------------------------------------------------------------------
  void Matrix ::printMatrix(char string[200])
  {
      cout<<string<<endl;
      
      cout.precision(10);
      for(int i=0; i<row ;i++)
     {
       for(int j=0;j<column;j++)
        {
            cout<<"  "<<matrix[i][j];
	} 
	cout<<endl;
     }
 cout<<endl;
 cout<<endl;
  
  }
  
  //----------------------------------------------------------------------------------------------------
  
  void Matrix::printMatrix()
  {
  
   
  cout.precision(10);
     for(int i=0; i<row ;i++)
     {
       for(int j=0;j<column;j++)
        {
            cout<<"  "<<matrix[i][j];
	} 
	cout<<endl;
     }
 cout<<endl;
 cout<<endl;
     
  }
  
  
 //---------------------------------------------------------------------------------------------------
  
  void Matrix::useDefault()
  {
   
   row=3;
   column=3;
   
   matrix[0][0]=5;    matrix[0][1]=2;	matrix[0][2]=1;//	matrixA[0][3]=7;
   matrix[1][0]=1;     matrix[1][1]=3;	matrix[1][2]=-1;//	matrixA[1][3]=5;
   matrix[2][0]=2;     matrix[2][1]=1;	matrix[2][2]=4;//	matrixA[2][3]=9;
  // matrixA[3][0]=7;     matrixA[3][1]=5;	matrixA[3][2]=9;	matrixA[3][3]=10;
   printMatrix();   
  
  } 
  
  
  
//---------------------------------------------------------------------------------------------------
 void Matrix::newElement()
 {
      cout<<"Enter New Element";
     
     for(int i=0; i<row ;i++)
     {
       for(int j=0;j<column;j++)
        {
            cin>>matrix[i][j];
	} 
	cout<<endl;
     }
   
       cout<<"Element stored ";
   
 
 }
 
 
 //---------------------------------------------------------------------------------------------
 void Matrix::swapRow(int currRow,int nextRow)
 {
  double temp;
  
       for(int j=0;j<column;j++)
        {
          temp=matrix[currRow][j];
	  matrix[currRow][j]=matrix[nextRow][j];
	  matrix[nextRow][j]=temp;
	
	} 
 }

 //--------------------------------------------------------------------------------------------
 
 
  Matrix Matrix::operator-(const Matrix B)  
  {
   Matrix C;
        if(row!=B.row || column!=B.column)   
        {
	  cout<<"ERROR: Matrix Are Not Of The Same Size ";
	  return B;
        } 
    
      for(int i=0;i<row;i++)
        for(int j=0;j<column;j++)
	 C.matrix[i][j]=matrix[i][j]-B.matrix[i][j];
	  	  	 
   return C;         
  
  }
 
//----------------------------------------------------------------------------------------------  
  Matrix Matrix::operator*(const Matrix B) 
 {
  
  Matrix C(row,B.column); 
  
    if(column!=B.row)
    {
      cout<<"Can not multiply two matrices"<<endl;
      return B;
    }  
    
    
    
   for(int i=0;i<row;i++)
    {
       
       for(int j=0;j<B.column;j++)
       {
       	   
         C.matrix[i][j]=0;
	 
         for(int k=0;k<column;k++)
	    C.matrix[i][j]=C.matrix[i][j]+(matrix[i][k]*B.matrix[k][j]);            
           
       }

     }
 
    return C;
 
 }
 
//----------------------------------------------------------------------------------------------------
  

 int Matrix::operator==(Matrix B)
 { 
     if(( row != B.getRowSize() ) || ( column != B.getColumnSize() ))
   
       return 0;
  
   for(int i=0;i<row;i++)
    {
      for(int j=0;j<column;j++)
       {
       
          if(matrix[i][j]!=B.matrix[i][j])
	   return 0;
          
       }
    }   
  
  return 1; 
 }
 
 //------------------------------------------------------------------------------------------
 
 void Matrix::setMatrixSize(int rowSize,int columnSize)
 {
 
    row=rowSize;
    column=columnSize;
 
 }
 
 //------------------------------------------------------------------------------------------
 
 int Matrix::getRowSize()
 {
   return row;  
 }
 
 //------------------------------------------------------------------------------------------
 
 int Matrix::getColumnSize()
 {
    return column;
 
 }
 
 //--------------------------------------------------------------------------------------------
  void Matrix::makeElement(int element)
  {
  
   for(int i=0;i<row;i++)
       for(int j=0;j<column;j++)
	   matrix[i][j]=element;
  
  }
 
  
//---------------------------------------------------------------------------------------------

 Matrix Matrix::getValueOfEquation(Matrix B)    
 {
    
    Matrix Xn(B.getRowSize(),B.getColumnSize());
    double X=0;
    Xn.makeElement(0);
   // Xn.printMatrix();
    
    cout<<endl<<endl;
    
   
    if(isUpperTriangular()==1)    
    {
           for(int i=(row-1);i>=0;i--) 
	   {
               for(int j=(column-1);j>=0;j--)
	         if(i!=j) 
		 X=X+(Xn.matrix[j][0]*matrix[i][j]);
                 Xn.matrix[i][0]=(B.matrix[i][0]-X)/matrix[i][i];  
	         X=0;
          }

    }
   else if(isLowerTriangular()==1)
   {
          
	  for(int i=0;i<row;i++) 
	   {
	      for(int j=0;j<column;j++)
	       if(i!=j)
		 X=X+(Xn.matrix[j][0]*matrix[i][j]);
      
	    Xn.matrix[i][0]=(B.matrix[i][0]-X)/matrix[i][i];  
	    X=0;
	   }
   }
   else
   {
      cout<<"The Augmented Matrix Is Not Triangularized"<<endl;
      return Xn;
   }
   
 return Xn;  
     
}
  
//--------------------------------------------------------------------------------------------------


int Matrix::isUpperTriangular()
{

 for(int i=0;i<row;i++)
   {
     for(int j=0;j<(i-1);j++)
      
       if(matrix[i][j]!=0)
        return 0;
   }
   return 1;


}    

//---------------------------------------------------------------------------------------------------

int Matrix::isLowerTriangular()
{

  for(int i=0;i<row;i++)
   {
     for(int j=i+1;j<column;j++)
       if(matrix[i][j]!=0)
        return 0;
 
   }
    	
 return 1;
 


}    

//--------------------------------------------------------------------------------------------------

int Matrix::isTolerable()
{
   
            
    for(int i=0;i<row;i++)    
    {
       for(int j=0;j<column;j++)
       {
          if(matrix[i][j]>0.0000001) 
           return 0;
       
       }
    
    }

return 1;

} 


//--------------------------------------------------------------------------------------------------

int Matrix::isTolerable(double tolerence)
{
   
            
    for(int i=0;i<row;i++)    
    {
       for(int j=0;j<column;j++)
       {
          if(matrix[i][j]>tolerence) 
           return 0;
       
       }
    
    }

return 1;

} 
  
  
